if (isnil "DM_Reinforcement_Men_Range") then {
	DM_Reinforcement_Men_Range = [700, 1100];
};
if (isnil "DM_Reinforcement_Veh_Range") then {
	DM_Reinforcement_Veh_Range = [1600, 2000];
};

XfMissionReinforcementPara = {
	private ["_side","_type","_startpoint","_attackpoint","_heliendpoint","_number_vehicles","_parachute_type","_make_jump","_stop_it","_delveccrew","_unit_type"];
	if (!isServer) exitWith {diag_log "Reinforcement is server only!"};

	_debug = d_mission_debug_messages;
	// _debug = true;
	_side = _this select 0;
	_attackpoint = _this select 1;
	_targetradius = _this select 2;
	_number_vehicles = _this select 3;
	_unit_type = _this select 4;
	_startpoint = [];
	_heliendpoint = [];
	
	if (_number_vehicles <= 0) then {_number_vehicles = 1};
	if (_number_vehicles > 5) then {_number_vehicles = 5};

	if (_debug) then {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementPara","Starting", _this];};

	if (count _attackpoint < 3) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementPara","One or more invalid arguments"];};
	if (_targetradius <= 0) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementPara","One or more invalid arguments"];};
	if (_number_vehicles <=0) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementPara","One or more invalid arguments"];};
	_side = switch (_side) do {case "EAST": {"EAST"};case "WEST": {"WEST"};case "GUER": {"GUER"};case "CIV": {"CIV"}; default{d_enemy_side};};

	d_should_be_there = _number_vehicles;

	// The groups of the paras
	if (isnil "d_c_attacking_grps") then {d_c_attacking_grps = [];};
	// The groups of the vehicles
	if (isnil "d_c_reinforcement_grps") then {d_c_reinforcement_grps = [];};

	_delveccrew = {
		private ["_crew_vec", "_vehicle", "_time"];
		_crew_vec = _this select 0;
		_vehicle = _this select 1;
		_time = _this select 2;
		sleep _time;
		{if (!isNull _x) then {_x setDamage 1}} forEach _crew_vec;
		sleep 1;
		if (!isNull _vehicle && ({isPlayer _x} count (crew _vehicle)) == 0) then {_vehicle setDamage 1};
	};

	_make_jump = {
		private ["_unit_type","_side","_vgrp", "_vehicle", "_attackpoint", "_heliendpoint", "_driver_vec", "_wp", "_stop_me", "_parachute_type", "_paragrp", "_unit_array", "_real_units", "_i", "_type", "_one_unit", "_para", "_grp_array","_crew_vec","_delveccrew"];
		_side = _this select 0;
		_vgrp = _this select 1;
		_vehicle = _this select 2;
		_attackpoint = _this select 3;
		_attackradius = _this select 4;
		_heliendpoint = _this select 5;
		_delveccrew = _this select 6;
		_unit_type = _this select 7;
		
		_debug = d_mission_debug_messages;
		// _debug = true;
		
		_startpos = position _vehicle;
		_driver_vec = driver _vehicle;
		_crew_vec = crew _vehicle;
		
		if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5, %6, %7, %8, %9, %10",diag_tickTime,"XfMissionReinforcementPara","Make Jump", _vgrp, _vehicle, _attackpoint, _attackradius, _heliendpoint, isnil "_delveccrew", typeof _driver_vec];};
		
		_wps = waypoints _vgrp;
		for [{_i = 0}, {_i < count _wps}, {_i = _i+ 1}] do {
			deleteWaypoint [_vgrp, _i];
		};
		_wp = _vgrp addWaypoint [_attackpoint, 0];
		_wp setWaypointBehaviour "CARELESS";
		_wp setWaypointSpeed "FULL";
		_wp setwaypointtype "MOVE";
		_wp setWaypointFormation "VEE";
		_vgrp setCurrentWayPoint _wp;
		_vehicle flyInHeight 100;
		_wp = _vgrp addWaypoint [_heliendpoint, 0];
		_wp setWaypointBehaviour "CARELESS";
		_wp setWaypointSpeed "FULL";
		_wp setwaypointtype "MOVE";
		
		_driver_vec doMove _attackpoint;
		sleep 10.0231;
		
		_stop_me = false;
		_checktime = time + 450;
		_has_dropped_troops = false;
		// While we didn't arrive at destination yet.
		while {_attackpoint distance (leader _vgrp) > 200} do {
			// If the vehicle got destroyed on the way... we remove it from the should_be_there array.
			if (_debug) then {diag_log Format["(%1)[%2]: %3: %4  dist:%5  pos:%6  dam:%7  fuel:%8",diag_tickTime,"XfMissionReinforcementPara","Should be there", d_should_be_there, (_attackpoint distance (leader _vgrp)), getPos _vehicle, damage _vehicle, fuel _vehicle];};
			if (isNull _vehicle || !alive _vehicle || !alive _driver_vec || !canMove _vehicle) exitWith { 
				(d_should_be_there == d_should_be_there - 1);
				if (_debug) then {diag_log Format["(%1)[%2]: %3: veh:%4  alive:%5  alive:%6  canmove:%7",diag_tickTime,"XfMissionReinforcementPara","Vehicle died", isNull _vehicle, alive _vehicle, alive _driver_vec, canMove _vehicle];};
			};
			sleep 0.01;
			// If it took too much time for the vehicle to arrive, we kill it.
			if (time > _checktime) then {
				if (_startpos distance position _vehicle < 500) then {
					if (_debug) then {diag_log Format["(%1)[%2]: %3: dist:%4  time:%5  checktime:%6",diag_tickTime,"XfMissionReinforcementPara","Vehicle too slow", (_startpos distance position _vehicle < 500), time, _checktime];};
					d_should_be_there = d_should_be_there - 1;
					[_crew_vec, _vehicle, 1 + random 1] spawn _delveccrew;
					_stop_me = true;
				} else {
					_checktime = time + 9999999;
				};
			};
			if (_stop_me) exitWith {};
			sleep 2.023;
		};
		if (_debug) then {diag_log Format["(%1)[%2]: %3: veh:%4  alive:%5  alive:%6  canmove:%7  stop:%8",diag_tickTime,"XfMissionReinforcementPara","Vehicle arrived", isNull _vehicle, alive _vehicle, alive _driver_vec, canMove _vehicle, _stop_me];};
		if (_stop_me) exitWith {};
		
		sleep 0.534;
		
		_parachute_type = "ParachuteEast";
		
		// If we reach this test, normally everyone is alive, but we check it for safety :)
		// Otherwise we kill everyone for safety too :)
		if (!isNull _vehicle && alive _vehicle && alive _driver_vec && canMove _vehicle && !_stop_me) then {
			if (_debug) then {diag_log Format["(%1)[%2]: %3 (%4) (%5)",diag_tickTime,"XfMissionReinforcementPara","Starting instantiating paras", (["reinforcement_canceled",False] call XNetGETJIP),(_vehicle distance _attackpoint)];};
			if (!(["reinforcement_canceled",False] call XNetGETJIP) && (_vehicle distance _attackpoint < 500) && !_has_dropped_troops) then {
				_cur_radius = _attackradius;
				_side_char = switch (_side) do {case "EAST": {"E"};case "WEST": {"W"};case "GUER": {"G"};case "CIV": {"W"}; default{"E"};};
				if (_unit_type < 0) then {_unit_type = round(random 4);};
				_real_units = [_side_char,1,_unit_type] call XfMissionGetRandomFootmenUnits;
				_paragrp = [_side] call x_creategroup;
				if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementPara","Creating para", _paragrp,_real_units];};
				sleep 0.1;
				
				_paragrp = [_real_units,true,_paragrp,(getMarkerPos "respawn_east"),[],False,"","FORM",False] call XfMissionCreateUnitGroup;
				if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementPara","Ejecting paras", _paragrp,count (units _paragrp)];};
				{
					_para = createVehicle [_parachute_type, position _vehicle, [], 20, 'NONE'];
					_para setpos [(position _vehicle) select 0,(position _vehicle) select 1,((position _vehicle) select 2)- 10];
					_para setDir random 360;
					_x moveInDriver _para;
					sleep 0.551;
				} foreach units _paragrp;
				
				d_c_attacking_grps set [count d_c_attacking_grps, _paragrp];
				_paragrp allowFleeing 0;
				_paragrp setCombatMode "RED";
				_paragrp setBehaviour "AWARE";
				sleep (5 + random 10);
				[_paragrp, _attackpoint,_attackradius ,_debug] spawn XfTaskPatrol;
				if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementPara","All units ejected", _paragrp,count (units _paragrp)];};
				_has_dropped_troops = true;

				_paragrp spawn {
					private ["_grp"];
					_grp = _this;
					while {alive leader _grp} do {
						// We wait for the current leader to die.
						waituntil { sleep 10; !alive leader _grp; };
						// When the leader is dead, we wait 10 seconds.
						// If no new leader has taken over command, it means that noone is left alive.
						// And thus the while loop will exit, otherwise it comes back in and starts to wait
						// for the new leader to die.
						sleep 10;
					};
					// When we leave the loop, we remove the group from the active attacking groups
					d_c_attacking_grps = d_c_attacking_grps - [_grp];
				};
				
				sleep 0.112;
				d_should_be_there = d_should_be_there - 1;
				
				_timeToLive = time + 300;
				_wps = waypoints _vgrp;
				for [{_i = 0}, {_i < count _wps}, {_i = _i+ 1}] do {
					deleteWaypoint [_vgrp, _i];
				};
				_wp = _vgrp addWaypoint [_heliendpoint, 100];
				_wp setWaypointBehaviour "CARELESS";
				_wp setWaypointSpeed "FULL";
				_wp setWaypointType "MOVE";
				_vgrp setCurrentWaypoint _wp;
				_driver_vec doMove _heliendpoint;
				while {(_heliendpoint distance (leader _vgrp) > 300) && (_timeToLive > time)} do {
					if (isNull _vehicle || !alive _vehicle || !alive _driver_vec || !canMove _vehicle) exitWith {};
					sleep 5.123;
				};
				
				if (!isNull _vehicle && (_heliendpoint distance _vehicle) > 300) then {
					[_crew_vec, _vehicle, 240 + random 100] spawn _delveccrew;
				} else {
					_vehicle call XfDelVecAndCrew;
				};
				if (!isNull _driver_vec) then {_driver_vec setDamage 1.1};
			};
		} else {
			[_crew_vec, _vehicle, 240 + random 100] spawn _delveccrew;
		};
		if (_debug) then {diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementPara","Ending MakeJump"];};
	};

	_lhd = FLAG_BASE;
	If (!isnil "LHD_CENTER") then {_lhd = LHD_CENTER;};
	_startpoint = [];
	_heliendpoint = [];
	if (_side == d_own_side && (!isnil "LHD_CENTER")) then {
		diag_log Format["(%1)[%2]: %3 (%4)",diag_tickTime,"XfMissionReinforcementPara","Own Side",(getPos LHD_CENTER)];
		_startpoint = [(getPos LHD_CENTER), 200] call XfGetRanPointCircleAir;
		_heliendpoint = _startpoint;
	};
	If ((count _startpoint < 3) || (count _heliendpoint < 3)) then {
		_startpoint = call XfGetRanPointOuterAir;
		while {(_startpoint distance FLAG_BASE < 2500) || (_startpoint distance _lhd < 2500)} do {
			_startpoint = call XfGetRanPointOuterAir;
		};
		_heliendpoint = call XfGetRanPointOuterAir;
		while {(_heliendpoint distance FLAG_BASE < 2500) || (_heliendpoint distance _lhd < 2500)} do {
			_heliendpoint = call XfGetRanPointOuterAir;
		};
	};

	_side_char = switch (_side) do {case "EAST": {"E"};case "WEST": {"W"};case "GUER": {"G"};case "CIV": {"W"}; default{"E"};};
	_transporter_list = missionNamespace getVariable format ["d_air_transport_h_%1",_side_char];
	_stop_it = false;
	if (_debug) then {diag_log Format["(%1)[%2]: %3: %4 (%5) %6",diag_tickTime,"XfMissionReinforcementPara","Starting the for loop", _number_vehicles,(["reinforcement_canceled",False] call XNetGETJIP),_transporter_list];};
	for "_i" from 1 to _number_vehicles do {
		if ((["reinforcement_canceled",False] call XNetGETJIP)) exitWith {_stop_it = true};
		_vgrp = [_side] call x_creategroup;
		_heli_type = _transporter_list call XfRandomArrayVal;
		_spos = [_startpoint select 0, _startpoint select 1, 300];
		_cdir = [_spos, _attackpoint] call XfDirTo;
		_veca = [_spos, _cdir, _heli_type, _vgrp] call XfSpawnVehicle;
		_vehicle = _veca select 0;
		_vehicle setVariable ["asr_ai_sys_aiskill_exclude", true];
		{
			_x disableAI "TARGET";
			_x disableAI "AUTOTARGET";
			_x AllowFleeing 0;
			_x setVariable ["zeu_AIBypass", true];
			_x setVariable ["asr_ai_sys_aiskill_exclude", true];
		} foreach crew _vehicle;
		_marker_text = localize "STR_MF_UNKNOWNAIRCONTACT";
		_marker_color = "ColorRed";
		If (_side == d_own_side) then {
			_marker_color = "ColorGreen";
			_marker_text = localize "STR_MF_REINFORCEMENTAIRCONTACT";
		};
		// [_vehicle,_marker_text,_marker_color] spawn XfAirMarkerMove;
		[(group (driver _vehicle)), _marker_text,_marker_color,"Air","WithAntiAirRadar"] spawn XfGroupMarkerMove;
		if (d_LockAir == 0) then {_vehicle lock true};
		sleep 5.012;
		
		_vehicle flyInHeight 100;
		if (_debug) then {diag_log Format["(%1)[%2]: %3: %4 (%5) %6 %7",diag_tickTime,"XfMissionReinforcementPara","Vehicle instantiated", typeof _vehicle, count crew _vehicle, _vgrp, _side];};
		if ((["reinforcement_canceled",False] call XNetGETJIP)) exitWith {_stop_it = true};

		d_c_reinforcement_grps set [count d_c_reinforcement_grps, _vgrp];
		_vgrp spawn {
			private ["_grp"];
			_grp = _this;
			while {alive leader _grp} do {
				// We wait for the current leader to die.
				waituntil { sleep 10; !alive leader _grp; };
				// When the leader is dead, we wait 10 seconds.
				// If no new leader has taken over command, it means that noone is left alive.
				// And thus the while loop will exit, otherwise it comes back in and starts to wait
				// for the new leader to die.
				sleep 10;
			};
			// When we leave the loop, we remove the group from the active reinforcement groups on the way.
			d_c_reinforcement_grps = d_c_reinforcement_grps - [_grp];
		};
		
		[_side,_vgrp,_vehicle,_attackpoint,_targetradius,_heliendpoint, _delveccrew,_unit_type] spawn _make_jump;
		
		sleep 40 + random 30;
	};

	if (_stop_it) exitWith {};

	if (_debug) then {diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementPara","Call ended"];};
};

XfMissionReinforcementMen = {
	private ["_men_type","_unit_type","_i","_completion_radius","_leader","_wp","_own_side","_reinfgrp","_real_units","_side_char","_lhd","_lst","_density","_height","_helper",
			 "_best_spot","_spot","_tries1","_tries2","_start_pos","_number_groups","_targetradius","_attackpoint","_side","_debug","_reinf_lower_range","_reinf_higher_range",
			 "_reinforcement_groups"];
	if (!isServer) exitWith {diag_log "Reinforcement is server only!"};
	
	_debug = d_mission_debug_messages;

	_side = _this select 0;
	_attackpoint = _this select 1;
	_targetradius = _this select 2;
	_number_groups = _this select 3;
	_unit_type = _this select 4;
	_start_pos = _this select 5;
	_reinforcement_groups = [];
	
	if (_number_groups <= 0) then {_number_groups = 1};
	
	if (isnil "d_c_attacking_grps") then {d_c_attacking_grps = [];};

	if (_debug) then {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementMen","Starting", _this];};

	if (count _attackpoint < 3) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementMen","One or more invalid arguments"];};
	if (_targetradius <= 0) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementMen","One or more invalid arguments"];};
	if (_number_groups <=0) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementMen","One or more invalid arguments"];};
	_side = switch (_side) do {case "EAST": {"EAST"};case "WEST": {"WEST"};case "GUER": {"GUER"};case "CIV": {"CIV"}; default{d_enemy_side};};
	
	if (isNil "_start_pos") then {_start_pos = [];};
	if (typename _start_pos != "ARRAY") then {_start_pos = [];};
	if (count _start_pos < 3) then {_start_pos = [];};
	if (count _start_pos == 3) then {
		if (!(surfaceiswater [(_start_pos select 0), (_start_pos select 1)])) then {
			_helper = "RoadCone" createVehicleLocal [(_start_pos select 0), (_start_pos select 1), 0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope > 0.5) then {_start_pos = [];};
			} else {
				_start_pos = [];
			};
			deleteVehicle _helper;
		} else {
			_start_pos = [];
		};
	};

	_tries1 = 30;
	_lhd = FLAG_BASE;
	If (!isnil "LHD_CENTER") then {_lhd = LHD_CENTER;};
	_own_side = switch (d_own_side) do {case "EAST": {east};case "WEST": {west};case "GUER": {resistance};case "CIV": {civilian}; default{west};};
	if (count _start_pos < 3) then {
		// Used to know if a spot is good:
		// 1) The position
		// 2) The height, we want a low point
		// 3) The "density" of the spot, this is the number of player units in the vicinity modulated by their distance.
		_best_spot = [[],2000,100000000];
		_reinf_lower_range = DM_Reinforcement_Men_Range select 0;
		_reinf_higher_range = DM_Reinforcement_Men_Range select 1;
		while { _tries1 > 0 } do {
			_spot = [_attackpoint, _reinf_higher_range, _reinf_lower_range] call XfGetRanPointCircle;
			if (count _spot > 0) then {
				_tries2 = 20;
				// We check that we are far enough from the base and LHD.
				// If we are spawning units of our own side, this check is ignored.
				// If the target area is within the base, the check is ignored (even for enemies). Otherwise you can't make enemies attack the base :)
				while {(((_spot distance FLAG_BASE < 1000) || (_spot distance _lhd < 1000)) && ((_attackpoint distance FLAG_BASE) > 200) && (_side != d_own_side) && (_tries2 > 0))} do {
					_spot = [_attackpoint, _reinf_higher_range, _reinf_lower_range] call XfGetRanPointCircle;
					_tries2 = _tries2 - 1;
				};
				if (count _spot == 3) then {
					if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementMen","Testing spot", _spot]; };
					_helper = "RoadCone" createVehicleLocal _spot;
					_height = (getPosASL _helper) select 2;
					deleteVehicle _helper;
					if ((_height < (_best_spot select 1)) || (_height - (_best_spot select 1)) < 50) then {
						_lst = nearestObjects [_spot, ["Man","Car","Tank","Ship"], 400];
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"XfMissionReinforcementMen","Acceptable height", _height,count _lst]; };
						_density = 0;
						{
							if ((side _x) == _own_side) then {
								if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"XfMissionReinforcementMen","Own Side", _x,(isplayer _x)]; };
								if (isplayer _x) then {
									// If a humen player is present, then we highly increase the density to reject as much as possible those spots
									_density = _density + (10000 / (_x distance _spot));
								} else {
									_density = _density + (2000 / (_x distance _spot));
								};
							};
						} foreach _lst;
						if (_density < (_best_spot select 2)) then {
							// We update the best spot
							_best_spot = [_spot, _height, _density];
							// We lower the tries count to narrow a good spot more quickly
							_tries1 = _tries1 - 1;
							if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"XfMissionReinforcementMen","New best spot", _best_spot,_tries1]; };
						};
					} else {
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementMen","Unacceptable height", _height]; };
					};
				};
			};
			_tries1 = _tries1 - 1;
		};
		_start_pos = _best_spot select 0;
	};
	if (count _start_pos < 3) exitWith {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementMen","Could not find a starting position", _this];};
	
	// If we have a road nearby, it's better to start on it to avoid being blocked.
	_roads = _start_pos nearRoads 100;
	if (count _roads > 0) then {
		_start_pos = getPos (_roads call XfRandomArrayVal);
	};
	
	_side_char = switch (_side) do {case "EAST": {"E"};case "WEST": {"W"};case "GUER": {"G"};case "CIV": {"W"}; default{"E"};};
	
	_completion_radius = _targetradius;
	If (_completion_radius < 350) then { _completion_radius = 350 };
	
	for "_i" from 1 to _number_groups do {
		_men_type = _unit_type;
		if (_men_type < 0) then {_men_type = round(random 4);};
		_real_units = [_side_char,1,_men_type] call XfMissionGetRandomFootmenUnits;
		_reinfgrp = [_side] call x_creategroup;
		_reinfgrp allowFleeing 0;
		_reinfgrp setCombatMode "RED";
		_reinfgrp setBehaviour "CARELESS";
		_reinfgrp setSpeedMode "FULL";
		if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementMen","Created units", _reinfgrp,_real_units];};
		sleep 0.1;
		
		_reinfgrp = [_real_units,true,_reinfgrp,_start_pos,[],False,"","FORM",False] call XfMissionCreateUnitGroup;
		// We prepare the next start position to ensure it will be empty.
		_spot = _start_pos findEmptyPosition [0,30];
		if (count _spot == 3) then { _start_pos = _spot};
		if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementMen","All units created", _reinfgrp,count (units _reinfgrp)];};
		sleep 1.234;
		while {(count (waypoints _reinfgrp) > 1)} do {
			deleteWaypoint [_reinfgrp, 1];
		};
		_wp = _reinfgrp addWaypoint [_start_pos, 100];
		_wp setWaypointSpeed "FULL";
		_wp setWaypointBehaviour "CARELESS";
		_wp setWaypointCombatMode "RED";
		_wp setWaypointCompletionRadius (100);
		_reinfgrp setCurrentWaypoint _wp;
		
		[_reinfgrp, 0] setWaypointSpeed "FULL";
		[_reinfgrp, 0] setWaypointBehaviour "CARELESS";
		_reinfgrp allowFleeing 0;
		_reinfgrp setCombatMode "RED";
		_reinfgrp setBehaviour "CARELESS";
		_reinfgrp setSpeedMode "FULL";
		_leader = leader _reinfgrp;
		_wp = _reinfgrp addWaypoint [_attackpoint, _targetradius];
		_wp setWaypointSpeed "FULL";
		_wp setWaypointBehaviour "CARELESS";
		_wp setWaypointCombatMode "RED";
		_wp setWaypointCompletionRadius (_completion_radius);
		_leader doMove _attackpoint;
		_reinfgrp setCurrentWaypoint _wp;
		{
			_x setCombatMode "RED";
			_x setBehaviour "CARELESS";
			_x setSpeedMode "FULL";
			if (_x != leader _reinfgrp) then {
				_x doFollow (leader _reinfgrp);
			} else {
				_x doMove _attackpoint;
			};
		} foreach (units _reinfgrp);
		
		d_c_attacking_grps set [count d_c_attacking_grps, _reinfgrp];
		_reinforcement_groups set [count _reinforcement_groups, _reinfgrp];
		
		[_reinfgrp, _attackpoint,_targetradius ,_debug,_completion_radius] spawn {
			private ["_reinfgrp", "_attackpoint","_targetradius" ,"_debug","_completion_radius"];
			_reinfgrp = _this select 0; _attackpoint = _this select 1; _targetradius = _this select 2; 
			_debug = _this select 3; _completion_radius = _this select 4; 
			waituntil {sleep 5; (leader _reinfgrp) doMove _attackpoint; (!alive (leader _reinfgrp)) || (((leader _reinfgrp) distance _attackpoint) < (_completion_radius))};
			sleep 3;
			if (alive (leader _reinfgrp)) then {
				[_reinfgrp, _attackpoint,_targetradius ,_debug] spawn XfTaskPatrol;
				while {alive leader _reinfgrp} do {
					// We wait for the current leader to die.
					waituntil { sleep 10; !alive leader _reinfgrp; };
					// When the leader is dead, we wait 10 seconds.
					// If no new leader has taken over command, it means that noone is left alive.
					// And thus the while loop will exit, otherwise it comes back in and starts to wait
					// for the new leader to die.
					sleep 10;
				};
				// When we leave the loop, we remove the group from the active attacking groups
				d_c_attacking_grps = d_c_attacking_grps - [_reinfgrp];
			};
		};
	};
	if (_debug) then {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementMen","Ending Function", _number_groups];};
	_reinforcement_groups;
};


XfMissionReinforcementVeh = {
	private ["_veh_type","_unit_type","_i","_roads","_completion_radius","_leader","_wp","_own_side","_reinfgrp","_real_units","_side_char","_lhd","_lst","_density","_height",
			 "_helper","_best_spot","_spot","_tries1","_tries2","_start_pos","_number_groups","_targetradius","_attackpoint","_side","_debug","_reinf_lower_range","_reinf_higher_range",
			 "_reinforcement_groups"];
	if (!isServer) exitWith {diag_log "Reinforcement is server only!"};

	_debug = d_mission_debug_messages;

	_side = _this select 0;
	_attackpoint = _this select 1;
	_targetradius = _this select 2;
	_number_groups = _this select 3;
	_unit_type = _this select 4;
	_start_pos = _this select 5;
	_reinforcement_groups = [];
	
	if (_number_groups <= 0) then {_number_groups = 1};
	if (_number_groups > 5) then {_number_groups = 5};

	if (isnil "d_c_attacking_grps") then {d_c_attacking_grps = [];};

	if (_debug) then {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementVeh","Starting", _this];};

	if (count _attackpoint < 3) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementVeh","One or more invalid arguments"];};
	if (_targetradius <= 0) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementVeh","One or more invalid arguments"];};
	if (_number_groups <=0) exitWith{diag_log Format["(%1)[%2]: %3",diag_tickTime,"XfMissionReinforcementVeh","One or more invalid arguments"];};
	_side = switch (_side) do {case "EAST": {"EAST"};case "WEST": {"WEST"};case "GUER": {"GUER"};case "CIV": {"CIV"}; default{d_enemy_side};};

	if (isNil "_start_pos") then {_start_pos = [];};
	if (typename _start_pos != "ARRAY") then {_start_pos = [];};
	if (count _start_pos < 3) then {_start_pos = [];};
	if (count _start_pos == 3) then {
		if (!(surfaceiswater [(_start_pos select 0), (_start_pos select 1)])) then {
			_helper = "RoadCone" createVehicleLocal [(_start_pos select 0), (_start_pos select 1), 0];
			if (!(surfaceIsWater [getPosASL _helper select 0, getPosASL _helper select 1])) then {
				_slope = [position _helper, 5] call XfGetSlope;
				if (_slope > 0.5) then {_start_pos = [];};
			} else {
				_start_pos = [];
			};
			deleteVehicle _helper;
		} else {
			_start_pos = [];
		};
	};
	
	_tries1 = 20;
	_lhd = FLAG_BASE;
	If (!isnil "LHD_CENTER") then {_lhd = LHD_CENTER;};
	_own_side = switch (d_own_side) do {case "EAST": {east};case "WEST": {west};case "GUER": {resistance};case "CIV": {civilian}; default{west};};
	if (count _start_pos < 3) then {
		// Used to know if a spot is good:
		// 1) The position
		// 2) The height, we want a low point
		// 3) The "density" of the spot, this is the number of player units in the vicinity modulated by their distance.
		_best_spot = [[],2000,10000000];
		_reinf_lower_range = DM_Reinforcement_Veh_Range select 0;
		_reinf_higher_range = DM_Reinforcement_Veh_Range select 1;
		while { _tries1 > 0 } do {
			_spot = [_attackpoint, _reinf_higher_range, _reinf_lower_range] call XfGetRanPointCircle;
			_tries2 = 40;
			// We check that we are far enough from the base and LHD.
			// If we are spawning units of our own side, this check is ignored.
			// If the target area is within the base, the check is ignored (even for enemies). Otherwise you can't make enemies attack the base :)
			while {(((_spot distance FLAG_BASE < 1000) || (_spot distance _lhd < 1000)) && ((_attackpoint distance FLAG_BASE) > 200) && (_side != d_own_side) && (_tries2 > 0) && (count (_spot nearRoads 200) <= 0))} do {
				_spot = [_attackpoint, _reinf_higher_range, _reinf_lower_range] call XfGetRanPointCircle;
				_tries2 = _tries2 - 1;
			};
			if (count _spot == 3) then {
				_roads = (_spot nearRoads 200);
				if (count _roads > 0) then {
					{
						_spot = (getPos _x) findEmptyPosition [0,30];
						if (count _spot == 3) exitWith {};
					} foreach _roads;
				} else {
					_spot = _spot findEmptyPosition [0,200];
				};
				if (count _spot == 3) then {
					if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementVeh","Testing spot", _spot]; };
					_helper = "RoadCone" createVehicleLocal _spot;
					_height = (getPosASL _helper) select 2;
					deleteVehicle _helper;
					if ((_height < (_best_spot select 1)) || (_height - (_best_spot select 1)) < 50) then {
						_lst = nearestObjects [_spot, ["Man","Car","Tank","Ship"], 400];
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"XfMissionReinforcementVeh","Acceptable height", _height,count _lst]; };
						_density = 0;
						{
							if ((side _x) == _own_side) then {
								if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"XfMissionReinforcementVeh","Own Side", _x,(isplayer _x)]; };
								if (isplayer _x) then {
									// If a humen player is present, then we highly increase the density to reject as much as possible those spots
									_density = _density + (10000 / (_x distance _spot));
								} else {
									_density = _density + (2000 / (_x distance _spot));
								};
							};
						} foreach _lst;
						if (_density < (_best_spot select 2)) then {
							// We update the best spot
							_best_spot = [_spot, _height, _density];
							// We lower the tries count to narrow a good spot more quickly
							_tries1 = _tries1 - 1;
							if (_debug) then { diag_log Format["(%1)[%2]: %3: %4 (%5)",diag_tickTime,"XfMissionReinforcementVeh","New best spot", _best_spot,_tries1]; };
						};
					} else {
						if (_debug) then { diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementVeh","Unacceptable height", _height]; };
					};
				};
			};
			_tries1 = _tries1 - 1;
		};
		_start_pos = _best_spot select 0;
	};
	if (count _start_pos <= 0) exitWith {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementVeh","Could not find a starting position", _this];};
	_side_char = switch (_side) do {case "EAST": {"E"};case "WEST": {"W"};case "GUER": {"G"};case "CIV": {"W"}; default{"E"};};
	
	_completion_radius = _targetradius;
	If (_completion_radius < 350) then { _completion_radius = 350 };
	for "_i" from 1 to _number_groups do {
		_veh_type = _unit_type;
		if (_veh_type < 0) then { _veh_type = (1 + floor(random 5));};
		_real_units = [_side_char,1,_veh_type] call XfMissionGetRandomVehicleUnits;
		_reinfgrp = [_side] call x_creategroup;
		_reinfgrp allowFleeing 0;
		_reinfgrp setCombatMode "WHITE";
		_reinfgrp setBehaviour "CARELESS";
		_reinfgrp setSpeedMode "FULL";
		if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementVeh","Created units", _reinfgrp,_real_units];};
		sleep 0.1;
		
		_reinfgrp = [_real_units,false,_reinfgrp,_start_pos,[],False,"","FORM",False] call XfMissionCreateUnitGroup;
		// We prepare the next start position to ensure it will be empty.
		_spot = _start_pos findEmptyPosition [0,30];
		if (count _spot == 3) then { _start_pos = _spot};
		if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementVeh","All units created", _reinfgrp,count (units _reinfgrp)];};
		sleep 1.345;
		while {(count (waypoints _reinfgrp) > 1)} do {
			deleteWaypoint [_reinfgrp, 1];
		};

		[_reinfgrp, 0] setWaypointSpeed "FULL";
		[_reinfgrp, 0] setWaypointBehaviour "CARELESS";
		_reinfgrp allowFleeing 0;
		_reinfgrp setCombatMode "WHITE";
		_reinfgrp setBehaviour "CARELESS";
		_reinfgrp setSpeedMode "FULL";
		_leader = leader _reinfgrp;
		_leader setCombatMode "WHITE";
		_leader setBehaviour "CARELESS";
		_leader setSpeedMode "FULL";
		_wp = _reinfgrp addWaypoint [_attackpoint, _targetradius];
		_wp setWaypointSpeed "FULL";
		_wp setWaypointBehaviour "CARELESS";
		_wp setWaypointCombatMode "WHITE";
		_wp setWaypointCompletionRadius (_completion_radius);
		
		d_c_attacking_grps set [count d_c_attacking_grps, _reinfgrp];
		_reinforcement_groups set [count _reinforcement_groups, _reinfgrp];
		
		[_reinfgrp, _attackpoint,_targetradius ,_debug,_completion_radius] spawn {
			private ["_reinfgrp", "_attackpoint","_targetradius" ,"_debug","_completion_radius"];
			_reinfgrp = _this select 0; _attackpoint = _this select 1; _targetradius = _this select 2; 
			_debug = _this select 3; _completion_radius = _this select 4; 
			waituntil {sleep 5; (!alive (leader _reinfgrp)) || (((leader _reinfgrp) distance _attackpoint) < (_completion_radius))};
			if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementVeh","Vehicle arrive", units _reinfgrp, [driver (vehicle leader _reinfgrp),gunner (vehicle leader _reinfgrp),commander (vehicle leader _reinfgrp)]];};
			{
				if (vehicle _x != _x) then {
					_vec = vehicle _x;
					_unit = _x;
					{
						_crew = _x;
						if ((_crew != (driver _vec)) && (_crew != (gunner _vec)) && (_crew != (commander _vec))) then {
							_crew leaveVehicle _vec;
							unassignVehicle _crew;
							if (_debug) then {diag_log Format["(%1)[%2]: %3: %4, %5",diag_tickTime,"XfMissionReinforcementVeh","Unassign Vehicle", _crew, [_vec, typeof _vec]];};
							sleep 0.12345;
						};
					} foreach assignedCargo _vec;
				};
			} foreach units _reinfgrp;
			[_reinfgrp, _attackpoint,_targetradius ,_debug] spawn XfTaskPatrol;
			while {alive leader _reinfgrp} do {
				// We wait for the current leader to die.
				waituntil { sleep 10; !alive leader _reinfgrp; };
				// When the leader is dead, we wait 10 seconds.
				// If no new leader has taken over command, it means that noone is left alive.
				// And thus the while loop will exit, otherwise it comes back in and starts to wait
				// for the new leader to die.
				sleep 10;
			};
			// When we leave the loop, we remove the group from the active attacking groups
			d_c_attacking_grps = d_c_attacking_grps - [_reinfgrp];
		};
	
	};
	if (_debug) then {diag_log Format["(%1)[%2]: %3: %4",diag_tickTime,"XfMissionReinforcementVeh","Ending Function", _number_groups];};
	_reinforcement_groups;
};